#include"LockFreeLinkedQueue.h"
#include<vector>
#include<unordered_map>
#include<mutex>
#include<condition_variable>
#include<thread>
using namespace std;

LockFreeLinkedQueue queue;
std::mutex mx;
condition_variable cond;
bool running = false;
atomic<int>cnt = 0;

const int pn = 100, cn = 100;
const int batch = 10;
const int num = 10;
unordered_map<int, int> counts[cn];

void produce() {
	{
		std::unique_lock<std::mutex>lock(mx);
		cond.wait(lock, []() {return running; });
	}
	for (int i = 0; i < batch; ++i) {
		for (int j = 0; j < num; ++j)
			queue.push(j);
	}
	++cnt;
}

void consume(int i) {
	unordered_map<int, int>& count = counts[i];
	{
		std::unique_lock<std::mutex>lock(mx);
		cond.wait(lock, []() {return running; });
	}
	int val;
	while (true) {
		bool flag = queue.tryPop(val);
		if (flag) ++count[val];
		else if (cnt== pn) break;
	}

}
int main() {
	std::atomic<std::shared_ptr<int*>>spt;
	cout << spt.is_lock_free() << endl;

	vector<thread>pThreads,cThreads;
	for (int i = 0; i < pn; ++i)
		pThreads.push_back(thread(&produce));
	for (int i = 0; i < cn; ++i) {
		cThreads.push_back(thread(&consume, i));
	}
	{
		std::lock_guard<std::mutex>guard(mx);
		running = true;
		cond.notify_all();
	}
	for (int i = 0; i < pn; ++i) pThreads[i].join();
	for (int i = 0; i < cn; ++i) cThreads[i].join();
	unordered_map<int, int> res;
	for (auto& count : counts) {
		for (auto& kv : count) {
			res[kv.first] += kv.second;
		}
	}
	for (auto& kv : res) {
		cout << kv.first << " " << kv.second << endl;

}